﻿using System;
using System.Windows.Media;
using System.Windows.Shapes;
using OpenLS.Drawing;

namespace OpenLS.Spreadsheet.UI
{
    internal class BorderFormatter
    {
        #region State enum

        public enum State
        {
            NonUniform,
            Enabled,
            Disabled
        }

        #endregion

        private readonly BorderStyle _borderStyle;
        private readonly BorderType _borderType;
        private readonly SpreadsheetColor _color;
        private readonly ColorScheme _colorScheme;
        private State _enabled;
        private Line _line;

        public BorderFormatter(BorderStyle borderStyle, SpreadsheetColor color, BorderType borderType,
                               ColorScheme colorScheme, State enabled)
        {
            _borderStyle = borderStyle;
            _color = color;
            _borderType = borderType;
            _colorScheme = colorScheme;
            _enabled = enabled;
        }

        public BorderType BorderType
        {
            get { return _borderType; }
        }

        public Pen Pen
        {
            get
            {
                var pen = new Pen(Brushes.Black, BorderStyleToThicknessConverter.StyleToThickness(BorderStyle));
                pen.DashStyle = BorderStyleToDashConverter.StyleToDash(BorderStyle);
                return pen;
            }
        }

        public Line Line
        {
            get
            {
                const int width = 210 - 18;
                const int height = 210 - 18;
                if (_line == null)
                {
                    _line = new Line
                                {
                                    Stroke = ColorToBrushConverter.GetBrush(_color, _colorScheme),
                                    StrokeThickness = BorderStyleToThicknessConverter.StyleToThickness(BorderStyle),
                                    StrokeDashArray = BorderStyleToDashConverter.StyleToDash(BorderStyle).Dashes
                                };
                    if (LineState == State.NonUniform)
                    {
                        Line.StrokeThickness = 3;
                        Line.Opacity = 0.5;
                    }
                    switch (BorderType)
                    {
                        case BorderType.TopEdge:
                            _line.X2 = width;
                            break;
                        case BorderType.BottomEdge:
                            _line.X2 = width;
                            _line.Y1 = height;
                            _line.Y2 = height;
                            break;
                        case BorderType.LeftEdge:
                            _line.Y2 = height;
                            break;
                        case BorderType.RightEdge:
                            _line.Y2 = height;
                            _line.X1 = width;
                            _line.X2 = width;
                            break;
                        case BorderType.InsideVertical:
                            _line.Y2 = height;
                            _line.X1 = width/2;
                            _line.X2 = width/2;
                            break;
                        case BorderType.InsideHorizontal:
                            _line.Y1 = height/2;
                            _line.Y2 = height/2;
                            _line.X2 = width;
                            break;
                        case BorderType.DiagonalDown
                            :
                            _line.Y2 = height;
                            _line.X2 = width;
                            break;
                        case BorderType.DiagonalUp:
                            _line.Y1 = height;
                            _line.X2 = width;
                            break;
                        case BorderType.All:
                        case BorderType.OutsideEdge:
                            throw new NotSupportedException();
                        default:
                            throw new NotSupportedException();
                    }
                }
                return _line;
            }
        }

        public SpreadsheetColor Color
        {
            get { return _color; }
        }

        public BorderStyle BorderStyle
        {
            get { return _borderStyle; }
        }

        public State LineState
        {
            get { return _enabled; }
            set
            {
                _enabled = value;
                switch (LineState)
                {
                    case State.Enabled:
                        Line.Opacity = 1;
                        Line.StrokeThickness = BorderStyleToThicknessConverter.StyleToThickness(BorderStyle);
                        break;
                    case State.NonUniform:
                        throw new NotSupportedException();
                    case State.Disabled:
                        Line.StrokeThickness = BorderStyleToThicknessConverter.StyleToThickness(BorderStyle);
                        Line.Opacity = 0;
                        break;
                    default:
                        throw new NotSupportedException();
                }
            }
        }

        public bool Compatible(BordersFormatter bordersFormatter)
        {
            return _borderStyle == bordersFormatter.BorderStyle && _color == bordersFormatter.Color;
        }

        public void Apply(Range selection)
        {
            switch (
                LineState)
            {
                case State.Enabled:
                    selection.SetBorder(new Border {Color = Color, Style = BorderStyle}, BorderType);
                    break;
                case State.Disabled:
                    selection.SetBorder(null, BorderType);
                    break;
                case State.NonUniform:
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
    }
}